// 知识点1：派生类的构造函数不仅要初始化自己的成员，还负责初始化派生类对象的基类部分，而派生类对象的基类部分是自动销毁的，派生类的析构函数只负责销毁自身派生类的成员，但是拷贝和移动操作，都会包含基类的部分

// 知识点2：定义派生类的拷贝和移动构造函数，需要在其初始值列表中显式的调用其基类的拷贝或移动构造函数，否则的话，派生类对象的基类部分会被默认初始化（派生类中定义拷贝和移动赋值运算符也是一样，需要在函数体中调用基类的相应成员）

// 知识点3：对象的销毁顺序正好和其创建的顺序相反，派生类的部分先被销毁，基类部分后被销毁

// 知识点4：如果构造函数或者析构函数调用了某个虚函数，那么我们应该执行与构造函数和析构函数所属类类型相对应的虚函数版本

#include <iostream>
#include <string>

using namespace std;
class Quote {
  friend double print_total(ostream &, const Quote &, size_t); //定义为友元函数
public:
  /*	Quote() = default;//C++11新特性*/
  Quote(); //默认构造函数
  Quote(const string &book, double sales_price)
      : BookNo(book), price(sales_price){}; //构造函数
  Quote(const Quote &quote1)
      : BookNo(quote1.BookNo), price(quote1.price) //拷贝构造函数
  {
    cout << "拷贝构造函数" << endl;
  }
  Quote &operator=(const Quote &quote2) //拷贝赋值运算符
  {
    //防止自赋值的情况
    if (this != &quote2) {
      BookNo = quote2.BookNo;
      price = quote2.price;
    }
    cout << "拷贝赋值运算符" << endl;
    return *this;
  }
  Quote(const Quote &&quote3)
      : BookNo(move(quote3.BookNo)), price(move(quote3.price)) //移动构造函数
  {
    cout << "移动构造函数" << endl;
  }
  Quote &operator=(const Quote &&quote4) noexcept //移动赋值运算符
  {
    if (this != &quote4) {
      BookNo = move(quote4.BookNo);
      price = move(quote4.price);
    }
    cout << "拷贝赋值运算符" << endl;
    return *this;
  }
  string isbn() const { return BookNo; }; //保存每本书籍的编号
  virtual double net_price(size_t n) const //定义为虚函数，让派生类自己定价
  {
    return n * price;
  }
  virtual void debug() {
    cout << "This is Quote Class" << endl;
    cout << "ISBN: " << BookNo << endl;
    cout << "Price: " << price << endl;
  }

private:
  string BookNo; //书籍的ISBN编号
protected:
  double price; //普通状态下不打折的价格，C++11不支持非静态变量的类内初始化
};
